import objc
import tempfile
import os
import struct
import threading
import traceback

from Foundation import *

kPathToDRC = '/usr/local/bin/drc'
kDRCOutputExtension = '.pcm'

curveLibrary = {
                # Perfectly flat curve
                'flat':[(0,0), (22050,0)],
                # B&K target listening curve
                'bk':[(0,-20), (10, -10), (20, 0), (400, 0), (12800, -5), (20000, -6), (21500, -10), (22050, -20)]
               }
               
class RoomCorrection(threading.Thread):
    """This thread class is responsible for calling drc """
    def __init__(self, settings, caller ):
        threading.Thread.__init__(self)
        self._settings = settings
        self._delegate = caller
        
    def run(self):
        pool = NSAutoreleasePool.alloc().init()
        
        self._delegate.drcStarted()
        
        p = os.popen(kPathToDRC + ' ' + self._settings.drcFilename)
        while 1:
            l = p.readline()
            if not l:
                break
            self._delegate.statusUpdate( l )
        
        self._delegate.drcEnded()

class RCSettings:
    impulseFilename = None
    targetCurveFilename = None
    micCurveFilename = None
    settingsTemplateFilename = None
    drcFilename = None
    outputFilename = None
    
    def __init__(self, path, record):        
        # First, dump the record's impulse out to a temp file
        (_, self.impulseFilename) = tempfile.mkstemp()
        impulseFile = open(self.impulseFilename, 'wb')
        vec = record.windowedImpulseResponse()
        for i in range(vec.length()):
            impulseFile.write(struct.pack('f', vec.componentAtIndex_(i)))
        impulseFile.close()
        
        self.targetCurveFilename = self.writeToTempFile( self.textFromCurve(curveLibrary['bk']) )
        self.micCurveFilename = self.writeToTempFile( self.textFromCurve(curveLibrary['flat']) )
        
        self.settingsTemplateFilename = unicode( NSBundle.bundleForClass_(objc.lookUpClass('DRCWindowController')).pathForResource_ofType_( "DRCTemplate", "drc" ) )
        self.outputFilename = '"' + path + '/' + record.comment() + kDRCOutputExtension + '"'
        
        print "Saving to " + self.outputFilename
        
        drcFileString = open( self.settingsTemplateFilename ).read() % {'outputFile':self.outputFilename, 
            'inputFile':self.impulseFilename, 'targetCurveFile':self.targetCurveFilename, 'micCurveFile':self.micCurveFilename }
        self.drcFilename = self.writeToTempFile( drcFileString )
        
    def textFromCurve( self, curve ):
        ret = []
        for f, v in curve:
            ret.append(str(f) + ' ' + str(v))
        return '\n'.join(ret)

    def writeToTempFile( self, aString ):
        (_, txtFilename) = tempfile.mkstemp()
        txtFile = open(txtFilename, 'wb')
        txtFile.write(aString)
        txtFile.close()
        return txtFilename

def performDRC( path, record, caller ):
    # spawn a thread for the drc to operate in, because it's a pretty long 
    # operation (20-30 seconds for me, on average)
    settings = RCSettings( path, record )
    rc = RoomCorrection(settings, caller)
    rc.start()
